package cn.com.zero.front.auth.controller;

import cn.com.zero.api.message.dubbo.IMessageService;
import cn.com.zero.base.constant.ZeroRegexPatternConstants;
import cn.com.zero.base.exception.ErrorCodeException;
import cn.com.zero.base.util.SensitiveInfoUtil;
import cn.com.zero.common.auth.security.po.AuthUserPO;
import cn.com.zero.common.auth.util.AuthUtil;
import cn.com.zero.front.auth.constant.FrontAuthConstants;
import cn.com.zero.front.auth.constant.ValidationRule;
import cn.com.zero.front.auth.po.AuthUserInfoPO;
import cn.com.zero.front.auth.service.IUserService;
import cn.com.zero.web.controller.BaseController;
import cn.com.zero.web.util.HttpRequestUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.Pattern;

/**
 * @author liuxh
 * @version 1.0.0
 * @Description 用户密码Controller
 * @createTime 2023/4/4 10:58
 */
@Validated
@RestController
@Api(tags = "用户密码接口")
@RequestMapping("/front/auth/userPwd")
public class UserPasswordController extends BaseController {

    private IMessageService messageService;
    private IUserService userService;


    @ApiOperation(value = "设置登录密码发送验证码")
    @PostMapping("/sendVerifyCode")
    public void sendVerifyCode() {
        String userId = AuthUtil.getUserIdFromRequest();
        try {
            // 获取当前登录用户的手机号
            AuthUserInfoPO userInfoPO = userService.getAuthUserInfoPO(userId);
            // 判断手机号是否为空
            String mobile = userInfoPO.getMobile();
            if (!StringUtils.hasLength(mobile)) {
                // 手机号为空，提示请用户先绑定手机号后再操作
                throw new ErrorCodeException(-20003L);
            }
            String mobilePhone = SensitiveInfoUtil.decryptMobile(mobile);
            // 发送验证码
            String requestIp = HttpRequestUtil.getRequestIp();
            messageService.sendVerificationCode(mobilePhone, FrontAuthConstants.CODE_MESSAGE_TYPE_RESET_PWD, requestIp);
            logger.debug("用户[{}]设置登录密码验证码发送成功，手机号：{}", userId, mobilePhone);
        } catch (Exception e) {
            logger.error("用户[{}]发送验证码异常:", userId, e);
        }
    }

    @ApiOperation(value = "设置/重置登录密码")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "verifyCode", required = true, value = "手机验证码"),
            @ApiImplicitParam(paramType = "query", name = "password", required = true, value = "新登录密码；不允许为空，客户端限制 6~18 位长度，字母+数字，需要在客户端对新密码进行 MD5 加密后传到服务端")
    })
    @PostMapping("/resetLoginPwd")
    public void resetLoginPwd(@RequestParam("verifyCode") String verifyCode,
                              @Pattern(regexp = ValidationRule.PASSWORD_EX) @RequestParam("password") String password) {

        //  获取当前登录用户的手机号
        String userId = AuthUtil.getUserIdFromRequest();
        // 获取当前登录用户的手机号
        AuthUserInfoPO userInfoPO = userService.getAuthUserInfoPO(userId);
        // 判断手机号是否为空
        String mobile = userInfoPO.getMobile();
        if (!StringUtils.hasLength(mobile)) {
            // 手机号为空，提示请用户先绑定手机号后再操作
            throw new ErrorCodeException(-20003L);
        }
        String mobilePhone = SensitiveInfoUtil.decryptMobile(mobile);

        Long res = messageService.checkVerificationCode(mobilePhone, FrontAuthConstants.CODE_MESSAGE_TYPE_RESET_PWD, verifyCode);
        if (res == null || res < 0) {
            throw new ErrorCodeException(-20001L);
        }

        // 重置登录密码
        userService.resetLoginPwd(userId, password);
    }


    // 忘记密码 发验证码
    @ApiOperation(value = "忘记登录密码发送验证码")
    @ApiImplicitParam(paramType = "query", name = "mobilePhone", required = true, value = "手机号，明文")
    @PostMapping("/forget/sendVerifyCode")
    public void sendVerifyCodeF(@Pattern(regexp = ZeroRegexPatternConstants.MOBILE_EX) @RequestParam("mobilePhone") String mobilePhone) {
        try {
            // 验证手机号对应的用户是否存在
            AuthUserPO userPO = userService.queryUserByMobilePhone(mobilePhone);
            if (userPO == null) {
                // 如果用户不存在则直接返回成功，防止客户通过忘记密码猜手机号在本系统中是否存在
                logger.debug("忘记登录密码发送验证码时，用户不存在，手机号：{}", mobilePhone);
                return;
            }
            // 发送验证码
            String requestIp = HttpRequestUtil.getRequestIp();
            messageService.sendVerificationCode(mobilePhone, FrontAuthConstants.CODE_MESSAGE_TYPE_FORGET_PWD, requestIp);
            logger.debug("用户[{}]忘记密码验证码发送成功，手机号：{}", userPO.getUserId(), mobilePhone);
        } catch (Exception e) {
            logger.error("手机号：" + mobilePhone + "发送验证码异常:" + e.getMessage());
        }

    }

    // 忘记密码 验证码 新密码
    @ApiOperation(value = "忘记密码设置新登录密码")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "mobilePhone", required = true, value = "手机号；明文"),
            @ApiImplicitParam(paramType = "query", name = "verifyCode", required = true, value = "手机验证码"),
            @ApiImplicitParam(paramType = "query", name = "password", required = true, value = "新密码；不允许为空，客户端限制 6~18 位长度，字母+数字，需要在客户端对新密码进行 MD5 加密后传到服务端")
    })
    @PostMapping("/forget/resetLoginPwd")
    public void resetLoginPwd(@Pattern(regexp = ZeroRegexPatternConstants.MOBILE_EX) @RequestParam(value = "mobilePhone") String mobilePhone,
                              @RequestParam("verifyCode") String verifyCode,
                              @Pattern(regexp = ValidationRule.PASSWORD_EX) @RequestParam("password") String password) {

        // 验证手机号对应的用户是否存在
        AuthUserPO userPO = userService.queryUserByMobilePhone(mobilePhone);
        if (userPO == null) {
            // 如果用户不存在则返回验证码不正确，防止客户通过忘记密码猜手机号在本系统中是否存在
            logger.debug("忘记登录密码发送验证码时，用户不存在，手机号：{}", mobilePhone);
            throw new ErrorCodeException(-20001L);
        }
        // 验证
        Long res = messageService.checkVerificationCode(mobilePhone, FrontAuthConstants.CODE_MESSAGE_TYPE_FORGET_PWD, verifyCode);
        if (res == null || res < 0) {
            throw new ErrorCodeException(-20001L);
        }

        // 重置登录密码
        userService.resetLoginPwd(userPO.getUserId(), password);
        //解锁用户清空登录错误次数
        userService.unlockCustomerByUserId(userPO.getUserId());
    }


    @ApiOperation(value = "修改登录密码")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "oldPassword", required = true, value = "原密码；不允许为空，需要在客户端对原密码进行 MD5 加密后传到服务端"),
            @ApiImplicitParam(paramType = "query", name = "newPassword", required = true, value = "新密码；不允许为空，客户端限制 6~18 位长度，字母+数字，需要在客户端对新密码进行 MD5 加密后传到服务端")
    })
    @PostMapping("/updateLoginPwd")
    public void updateLoginPwd(@RequestParam("oldPassword") String oldPassword,
                               @Pattern(regexp = ValidationRule.PASSWORD_EX) @RequestParam("newPassword") String newPassword) {
        // 获取用户ID
        String userId = AuthUtil.getUserIdFromRequest();

        // 通过用户ID查询用户密码登录信息
        AuthUserInfoPO authUserInfoPO = userService.getAuthUserInfoPO(userId);

        // 判断旧密码是否匹配
        boolean matchesPwd = SensitiveInfoUtil.matchesPwd(oldPassword, authUserInfoPO.getPassword());
        if (!matchesPwd) {
            throw new ErrorCodeException(-20004L); // 原密码不正确
        }
        // 修改密码
        userService.resetLoginPwd(userId, newPassword);
    }

    @Autowired
    public void setUserService(IUserService userService) {
        this.userService = userService;
    }

    @DubboReference
    public void setMessageService(IMessageService messageService) {
        this.messageService = messageService;
    }
}
